package com.cgq.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cgq.mapper.StockMapper;
import com.cgq.pojo.Stock;
import com.cgq.service.StockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * *  Author:陈国强
 * *  Description:
 * *  Date:2023/2/15 14:35
 */
@Service
//多例模式，单例模式是sington，proxyMode指定代理模式使用CGLIB代理->SpringBoot2.x版本之后
//@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
public class StockServiceImpl implements StockService {

    @Autowired
    private StockMapper mapper;

    private ReentrantLock lock = new ReentrantLock();

    //@Transactional

    @Override
    public String deduct(String product_code) {
        //进行jvm中的加锁操作
        lock.lock();
        //查询想要购买商品编号的信息
        try {
            Stock stock = mapper.selectOne(new QueryWrapper<Stock>().
                    eq("product_code", product_code));
            if (stock != null && stock.getCount() > 0) {
                //购买成功后，商品的库存余量-1
                stock.setCount(stock.getCount() - 1);
                //随后进行商品库存余量的数据更新操作
                int i = mapper.updateById(stock);
                System.err.println(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //必须要释放锁
            lock.unlock();
        }
        return "恭喜您抢到了该商品";
    }

    @Override
    public String deduct1(String product_code,Integer count) {

        try {
            //查询想要购买商品编号的信息
            int i = mapper.updateStock(product_code, count);
            if (i > 0){
                return "恭喜您抢到了该商品";
            }else {
                return "很遗憾,未抢到该商品";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "很遗憾,未抢到该商品";
    }


    //演示悲观锁减商品库存
    //@Transactional
    @Override
    public List<Stock> queryStock(String productCode) {
        //1.查询商品库存信息的同时将库存信息锁定
        List<Stock> stocks = mapper.queryStock(productCode);
        //2.由于数据库中存在不止一个仓，在这里不进行仓问题的分析，就以第一个仓为例
        Stock stock = stocks.get(0);
        //进行第一个仓的库存判断，如果第一个仓的库存不够，那么我们去选择第二个仓的数据

        List<Stock> stocks1 = mapper.queryStock(productCode);
        if (stock.getCount() <= 0){
            //在第一个仓没有库存的情况下，选择第二个仓的库存
            Stock stock1 = stocks.get(1);
            //判断库存是否充足
            if (stock1 != null && stock1.getCount() > 0){
                //3.充足的情况下，进行库存的扣减
                stock1.setCount(stock1.getCount() -1);
                int i = mapper.updateById(stock1);
                if (i == 1){
                    //再次进行库存信息的查询
                    stocks1 = mapper.queryStock(productCode);
                    return stocks1;
                }
            }
        }else {
            //判断库存是否充足

            if (stock != null && stock.getCount() > 0){
                //3.充足的情况下，进行库存的扣减
                stock.setCount(stock.getCount() -1);
                int i = mapper.updateById(stock);
                if (i == 1){
                    //再次进行库存信息的查询
                    stocks1 = mapper.queryStock(productCode);

                }
            }

        }
        return stocks1;
    }



    //演示乐观锁减商品库存
    //@Transactional
    @Override
    public List<Stock> queryStock1(String productCode) {
        //1.查询商品库存信息的同时将库存信息锁定
        //此时查询到的是一个根据product_code字段的商品信息。
        //对应得sql语句SELECT * FROM db_stock WHERE product_code = '1001'
        List<Stock> stocks = mapper.selectList(new QueryWrapper<Stock>().
                eq("product_code", productCode));

        //2.由于数据库中存在不止一个仓，在这里不进行仓问题的分析，就以第一个仓为例
        Stock stock = stocks.get(0);

        //进行第一个仓的库存判断，如果第一个仓的库存不够，那么我们去选择第二个仓的数据
        if (stock.getCount() <= 0){
            //在第一个仓没有库存的情况下，选择第二个仓的库存
            Stock stock1 = stocks.get(1);
            //判断库存是否充足
            if (stock1 != null && stock1.getCount() > 0){
                //3.充足的情况下，进行库存的扣减
                stock1.setCount(stock1.getCount()-1);

                //并且版本号也要加1
                Integer version = stock1.getVersion();//获取到当前版本号

                //版本号加1
                stock1.setVersion(version + 1);

                //进行数据更新操作
                UpdateWrapper<Stock> updateWrapper = new UpdateWrapper<Stock>().
                        eq("id", stock1.getId()).
                        eq("version",version);

                //执行数据更新受影响的行数
                int update = mapper.update(stock1,updateWrapper );

                //受影响的行数为1时
                if (update == 1){

                    //再次进行库存信息的查询
                    stocks = mapper.selectList(new QueryWrapper<Stock>().eq("product_code",productCode));

                    //返回更改后的商品信息
                    return stocks;
                }else{
                    //如果更新失败，就进行重试
                    //频繁的重试，容易导致暂存溢出，所以此时让其睡一会
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    this.queryStock(productCode);
                }
            }
        }else {
            //判断库存是否充足

            if (stock != null && stock.getCount() > 0){
                //3.充足的情况下，进行库存的扣减
                stock.setCount(stock.getCount() -1);
                //并且版本号也要加1
                Integer version = stock.getVersion();//获取到当前版本号

                //版本号加1
                stock.setVersion(version + 1);

                int i = mapper.update(stock, new UpdateWrapper<Stock>().eq("id", stock.getId()).eq("version",version));

                if (i == 1){
                    //再次进行库存信息的查询
                    stocks = mapper.selectList(new QueryWrapper<Stock>().eq("product_code",productCode));
                }else{
                    this.queryStock(productCode);
                }
            }

        }
        return stocks;
    }

}
